/*========================== begin_copyright_notice ============================

Copyright (C) 2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#include "../imf.h"
#pragma OPENCL FP_CONTRACT OFF

/*
//++
//  ALGORITHM DESCRIPTION
//  ---------------------
//
//  Case 2^13 <= x < OVERFLOW_BOUNDARY
//  ----------------------------------
//    Here we use algorithm based on the Stirling formula:
//      ln(GAMMA(x)) = ln(sqrt(2*Pi)) + (x-0.5)*ln(x) - x
//
//  Case 1 < x < 2^13
//  -----------------
//    To calculate ln(GAMMA(x)) for such arguments we use polynomial
//    approximation on following intervals: [1.0; 1.25), [1.25; 1.5),
//    [1.5, 1.75), [1.75; 2), [2; 4), [2^i; 2^(i+1)), i=1..8
//
//    Following variants of approximation and argument reduction are used:
//     1. [1.0; 1.25)
//        ln(GAMMA(x)) ~ (x-1.0)*P7(x)
//
//     2. [1.25; 1.5)
//        ln(GAMMA(x)) ~ ln(GAMMA(x0))+(x-x0)*P7(x-x0),
//        where x0 - point of local minimum on [1;2] rounded to nearest double
//        precision number.
//
//     3. [1.5; 1.75)
//        ln(GAMMA(x)) ~ P8(x)
//
//     4. [1.75; 2.0)
//        ln(GAMMA(x)) ~ (x-2)*P7(x)
//
//     5. [2; 4)
//        ln(GAMMA(x)) ~ (x-2)*P10(x)
//
//     6. [2^i; 2^(i+1)), i=2..8
//        ln(GAMMA(x)) ~ P10((x-2^i)/2^i)
//
//  Case -9 < x < 1
//  ---------------
//    Here we use the recursive formula:
//    ln(GAMMA(x)) = ln(GAMMA(x+1)) - ln(x)
//
//    Using this formula we reduce argument to base interval [1.0; 2.0]
//
//  Case -2^13 < x < -9
//  --------------------
//    Here we use the formula:
//    ln(GAMMA(x)) = ln(Pi/(|x|*GAMMA(|x|)*sin(Pi*|x|))) =
//    = -ln(|x|) - ln((GAMMA(|x|)) - ln(sin(Pi*r)/(Pi*r)) - ln(|r|)
//    where r = x - rounded_to_nearest(x), i.e |r| <= 0.5 and
//    ln(sin(Pi*r)/(Pi*r)) is approximated by 8-degree polynomial of r^2
//
//  Case x < -2^13
//  --------------
//    Here we use algorithm based on the Stirling formula:
//    ln(GAMMA(x)) = -ln(sqrt(2*Pi)) + (|x|-0.5)ln(x) - |x| -
//    - ln(sin(Pi*r)/(Pi*r)) - ln(|r|)
//    where r = x - rounded_to_nearest(x).
//
//  Neighbourhoods of negative roots
//  --------------------------------
//    Here we use polynomial approximation
//    ln(GAMMA(x-x0)) = ln(GAMMA(x0)) + (x-x0)*P14(x-x0),
//    where x0 is a root of ln(GAMMA(x)) rounded to nearest double
//    precision number.
//
//
//  Claculation of logarithm
//  ------------------------
//    Consider  x = 2^N * xf so
//    ln(x) = ln(frcpa(x)*x/frcpa(x))
//          = ln(1/frcpa(x)) + ln(frcpa(x)*x)
//
//    frcpa(x) = 2^(-N) * frcpa(xf)
//
//    ln(1/frcpa(x)) = -ln(2^(-N)) - ln(frcpa(xf))
//                   = N*ln(2) - ln(frcpa(xf))
//                   = N*ln(2) + ln(1/frcpa(xf))
//
//    ln(x) = ln(1/frcpa(x)) + ln(frcpa(x)*x) =
//          = N*ln(2) + ln(1/frcpa(xf)) + ln(frcpa(x)*x)
//          = N*ln(2) + T + ln(frcpa(x)*x)
//
//    Let r = 1 - frcpa(x)*x, note that r is quite small by
//    absolute value so
//
//    ln(x) = N*ln(2) + T + ln(1+r) ~ N*ln(2) + T + Series(r),
//    where T - is precomputed tabular value,
//    Series(r) = (P3*r + P2)*r^2 + (P1*r + 1)
//
//--
*/

// SPIRV intrinsics
// double SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(fabs, _f64, ) (double);
// float SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(log, _f32, ) (float);
// float SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(fma, _f32_f32_f32, ) (float, float, float);
// double SPIRV_OVERLOADABLE SPIRV_OCL_BUILTIN(fma, _f64_f64_f64, ) (double, double, double);

//
// Static data section:
//
//
// LUT log_fp64 data:
//

static __constant unsigned int __slgamma_ep_log_ones[] = { 0x3f800000, 0xbf800000 };
static __constant unsigned int __slgamma_ep_log_halfs[] = { 0x3f000000, 0xbf000000 };
static __constant unsigned int __slgamma_ep_log_zeros[] = { 0x00000000, 0x80000000 };
static __constant unsigned int __slgamma_ep_log_pone_nzero[] = { 0x3f800000, 0x80000000 };

static __constant double __slgamma_ep_log_table_256[256 * 2] = {
    6.24525388826670410e-10, 0.00195503421127796170, 2.96064357105772110e-10, 0.00587660819292068480, 7.25869983487591580e-09, 0.00981361418962478640,
        3.86437150052989690e-09, 0.01376619189977645900, 1.55869230756456920e-09, 0.01723755896091461200, 5.44849874059905220e-09,
        0.02121964097023010300, 4.22721371362978390e-10, 0.02521765232086181600, 2.18815188910284700e-09, 0.02872906625270843500,
        1.88147074138941820e-08, 0.03275725245475769000, 1.40625184453713400e-08, 0.03629529476165771500, 5.31573423083850000e-09,
        0.04035416245460510300, 2.82692471116201410e-08, 0.04391920566558837900, 2.12098434932020450e-08, 0.04749703407287597700,
        2.21715184841870480e-08, 0.05160170793533325200, 8.10890231659138890e-10, 0.05520719289779663100, 2.25574052921804340e-09,
        0.05882570147514343300, 2.05708339632569340e-09, 0.06245735287666320800, 3.64067531756524850e-08, 0.06610220670700073200,
        2.33386325146903620e-08, 0.06976044178009033200, 3.09649945180628580e-08, 0.07343208789825439500, 3.90736488190665430e-08,
        0.07711726427078247100, 2.85509247400559330e-08, 0.08081609010696411100, 2.90850401817173710e-08, 0.08399742841720581100,
        3.19472323262296670e-08, 0.08772182464599609400, 1.03421717504117640e-08, 0.09146016836166381800, 9.15353226418696250e-09,
        0.09521251916885376000, 2.17344561331841400e-08, 0.09844005107879638700, 7.63329650586261760e-09, 0.10221874713897705000,
        4.00709960199013040e-08, 0.10546898841857910000, 2.76193434896948180e-08, 0.10927438735961914000, 4.46871825118468030e-08,
        0.11254769563674927000, 2.31705379648647440e-08, 0.11583179235458374000, 2.97741830291567310e-08, 0.11967688798904419000,
        5.93390648555917520e-08, 0.12298446893692017000, 3.86483375191269860e-08, 0.12630307674407959000, 4.07983428391949040e-08,
        0.12963271141052246000, 6.06085314122088380e-08, 0.13353133201599121000, 5.85547411567173450e-08, 0.13688516616821289000,
        1.76703256773052630e-08, 0.14025032520294189000, 1.41696953811130220e-08, 0.14362680912017822000, 5.83259823325358470e-09,
        0.14701473712921143000, 7.04332320819018130e-08, 0.15041410923004150000, 4.81230888761681300e-08, 0.15382516384124756000,
        3.82624430647766620e-09, 0.15667665004730225000, 1.08401532975164310e-07, 0.16010904312133789000, 1.14680786759119260e-07,
        0.16355335712432861000, 1.04387517909591830e-07, 0.16700959205627441000, 4.08862549583531620e-08, 0.17047786712646484000,
        2.57048033484924600e-08, 0.17337727546691895000, 1.01855814543713160e-07, 0.17686760425567627000, 1.03021904632821480e-07,
        0.17978560924530029000, 8.64270897337268540e-09, 0.18329858779907227000, 1.95777984112222540e-08, 0.18682384490966797000,
        5.47721667673493310e-08, 0.18977105617523193000, 9.96326652247247150e-08, 0.19272696971893311000, 6.73286998183625900e-08,
        0.19628572463989258000, 2.98344563896227420e-08, 0.19926106929779053000, 3.27524951814188620e-09, 0.20284318923950195000,
        1.91877181711306580e-08, 0.20583808422088623000, 9.08450180865014300e-08, 0.20884191989898682000, 3.40404526791850280e-08,
        0.21185493469238281000, 6.88658573085511270e-08, 0.21548247337341309000, 8.95949296689811920e-08, 0.21851551532745361000,
        3.94632284049990770e-08, 0.22155785560607910000, 9.39967060390415720e-08, 0.22460937500000000000, 7.16105891230257220e-08,
        0.22767031192779541000, 2.96621771706489570e-08, 0.23074066638946533000, 2.60387125353950670e-08, 0.23382043838500977000,
        1.19163929004098930e-07, 0.23690962791442871000, 1.03768332043087580e-08, 0.24000859260559082000, 1.16822063979612020e-07,
        0.24311697483062744000, 2.17359869401166560e-08, 0.24623525142669678000, 2.41744246016829630e-08, 0.24936318397521973000,
        1.85345415246686110e-07, 0.25250077247619629000, 2.09407109992179950e-07, 0.25564837455749512000, 1.33684460353297330e-07,
        0.25817370414733887000, 2.11574289707605050e-07, 0.26133918762207031000, 9.00745434242104190e-08, 0.26451492309570313000,
        7.16537193724757780e-08, 0.26770067214965820000, 1.36420294840980400e-07, 0.27025651931762695000, 1.33126531978734040e-07,
        0.27346062660217285000, 1.77125091216931600e-07, 0.27667498588562012000, 1.86086768053735930e-07, 0.27925395965576172000,
        1.01567718915670430e-07, 0.28248715400695801000, 1.42604140553174540e-07, 0.28508114814758301000, 1.48571572555077840e-07,
        0.28833317756652832000, 1.60005498829090610e-07, 0.29094243049621582000, 2.49492772931465210e-09, 0.29421377182006836000,
        1.64198948898441940e-07, 0.29683828353881836000, 7.00432880303546960e-08, 0.30012893676757813000, 8.82584936568972090e-08,
        0.30276918411254883000, 1.81795236029213060e-07, 0.30541634559631348000, 1.11013626941557440e-07, 0.30873537063598633000,
        9.29045461883075650e-08, 0.31139850616455078000, 3.33744875697763770e-08, 0.31406879425048828000, 2.08920472516856840e-07,
        0.31674599647521973000, 1.09630273603698370e-07, 0.32010293006896973000, 6.08458071286488220e-08, 0.32279658317565918000,
        1.34608876925074000e-07, 0.32549738883972168000, 1.31905741875646990e-07, 0.32820558547973633000, 9.24622577605461360e-08,
        0.33092117309570313000, 5.63287946164216310e-08, 0.33364415168762207000, 4.01093181451374420e-08, 0.33705830574035645000,
        9.99579824458008530e-08, 0.33979797363281250000, 5.71461339235723670e-08, 0.34254527091979980000, 1.91562039059975030e-07,
        0.34529995918273926000, 6.81818993448106610e-08, 0.34806251525878906000, 2.06003713002673360e-07, 0.35083246231079102000,
        1.70702503085333340e-07, 0.35361027717590332000, 5.14570675925141230e-09, 0.35639595985412598000, 2.16368572495259350e-07,
        0.35848999023437500000, 1.05910955541374650e-07, 0.36128926277160645000, 2.23366176893820390e-07, 0.36409616470336914000,
        1.36132534455597020e-07, 0.36691117286682129000, 1.27238676615280290e-07, 0.36973404884338379000, 3.25494865767704650e-09,
        0.37256503105163574000, 4.79720113005438810e-08, 0.37540388107299805000, 1.97380526740140870e-07, 0.37753820419311523000,
        1.11226824788218490e-07, 0.38039135932922363000, 8.21400591371806070e-08, 0.38325262069702148000, 1.40843337820261590e-07,
        0.38540387153625488000, 2.05386255809989450e-07, 0.38827943801879883000, 2.18386348200994410e-07, 0.39116334915161133000,
        2.15703243158502060e-07, 0.39333176612854004000, 7.53725376880368670e-08, 0.39623045921325684000, 1.64288615668358410e-08,
        0.39913749694824219000, 2.26534217802063680e-07, 0.40132308006286621000, 1.12671138822034780e-08, 0.40424513816833496000,
        2.20799814236951490e-07, 0.40644192695617676000, 1.99717180482033070e-09, 0.40937900543212891000, 8.80127616840417480e-08,
        0.41158723831176758000, 2.08304072392656010e-08, 0.41453933715820313000, 1.00597284598910070e-07, 0.41675901412963867000,
        1.04189588570843410e-07, 0.41972637176513672000, 5.83892125869795740e-08, 0.42195773124694824000, 5.43781380061424610e-08,
        0.42494058609008789000, 3.98053197745310620e-09, 0.42718362808227539000, 1.54926007316971500e-07, 0.43018198013305664000,
        2.22810532956920800e-07, 0.43243670463562012000, 1.41066666758349060e-07, 0.43469667434692383000, 5.11664679802066330e-08,
        0.43771791458129883000, 2.82205261878278520e-08, 0.43998980522155762000, 1.71622158353766290e-07, 0.44226670265197754000,
        1.85585417763574140e-07, 0.44531083106994629000, 9.39830189819852280e-08, 0.44760012626647949000, 9.65126910307187050e-09,
        0.44989466667175293000, 1.95167365785787740e-07, 0.45219421386718750000, 1.09625517615474020e-07, 0.45526885986328125000,
        6.60037701972146410e-08, 0.45758104324340820000, 1.35555265533821640e-07, 0.45989847183227539000, 1.04755218690640980e-07,
        0.46222138404846191000, 2.37089883068808630e-07, 0.46454954147338867000, 4.86830442023486150e-08, 0.46766257286071777000,
        2.43568195380259370e-08, 0.47000360488891602000, 9.58242551872656280e-09, 0.47235012054443359000, 3.02000192400956270e-08,
        0.47470211982727051000, 1.12232517595981120e-07, 0.47705960273742676000, 4.34687457252428300e-08, 0.47942280769348145000,
        8.87209223253701030e-08, 0.48179149627685547000, 3.61521120072060810e-08, 0.48416590690612793000, 1.50952331510556910e-07,
        0.48654580116271973000, 2.21666044456975910e-07, 0.48893141746520996000, 3.70311523679313970e-08, 0.49132299423217773000,
        1.01236586752019280e-07, 0.49372005462646484000, 2.03412711562308440e-07, 0.49612283706665039000, 1.32888960173996590e-07,
        0.49853157997131348000, 1.56032916194247910e-07, 0.50094604492187500000, 6.25779429294442840e-08, 0.50336647033691406000,
        1.19299469270426280e-07, 0.50579261779785156000, 3.54761245816753320e-07, 0.50822448730468750000, 3.20898783504391710e-07,
        0.51066255569458008000, 4.66957123978575870e-08, 0.51310682296752930000, 9.68991021542283110e-09, 0.51473951339721680000,
        1.94635363645639260e-07, 0.51719331741333008000, 2.17577056070488450e-07, 0.51965332031250000000, 1.08290023009512570e-07,
        0.52211952209472656000, 3.73607287079975660e-07, 0.52459144592285156000, 9.00734143239616550e-08, 0.52707004547119141000,
        1.40977394245760550e-07, 0.52872562408447266000, 1.23077497290551900e-07, 0.53121423721313477000, 1.14854561346971720e-07,
        0.53370904922485352000, 1.47364374839112130e-07, 0.53621006011962891000, 1.54126848701644840e-07, 0.53788089752197266000,
        1.65227253774842730e-07, 0.54039239883422852000, 3.01024282318591700e-07, 0.54291009902954102000, 1.05713126525882410e-07,
        0.54459238052368164000, 3.61453692234045630e-07, 0.54712057113647461000, 3.50723872474122270e-07, 0.54965543746948242000,
        1.05644268037663280e-07, 0.55134916305541992000, 3.59093213483098230e-07, 0.55389451980590820000, 4.33494745317747000e-07,
        0.55644655227661133000, 2.94068094775690230e-07, 0.55815172195434570000, 3.03007642491224460e-07, 0.56071472167968750000,
        2.22123716575340900e-07, 0.56328439712524414000, 3.46973239880618110e-07, 0.56500101089477539000, 3.50866536202806000e-07,
        0.56758165359497070000, 2.46060613491704130e-07, 0.56930589675903320000, 4.30213208436756000e-07, 0.57189750671386719000,
        1.59818892595195750e-07, 0.57362937927246094000, 1.44118423962805140e-07, 0.57623243331909180000, 2.46193949175782990e-07,
        0.57884216308593750000, 1.32311227201802130e-07, 0.58058595657348633000, 1.91932458841501630e-07, 0.58320713043212891000,
        8.29831137800442700e-08, 0.58495855331420898000, 1.85492977982419940e-07, 0.58671283721923828000, 1.63337041978966180e-07,
        0.58935022354125977000, 3.65030880710986010e-07, 0.59111213684082031000, 6.59514810739575470e-08, 0.59376144409179688000,
        4.35223847714466180e-07, 0.59553098678588867000, 4.39331100602796470e-07, 0.59819173812866211000, 9.18141604571484480e-08,
        0.59996986389160156000, 2.69239084148394750e-08, 0.60264253616333008000, 4.63363830592733550e-07, 0.60442781448364258000,
        2.79588976991886460e-07, 0.60621690750122070000, 2.96598682744135890e-07, 0.60890626907348633000, 4.30261168118990740e-08,
        0.61070346832275391000, 1.63258047880683210e-07, 0.61250352859497070000, 4.73982988088037060e-07, 0.61520957946777344000,
        1.49398707322060770e-07, 0.61701822280883789000, 2.39733044370533100e-07, 0.61882972717285156000, 1.06352428678991630e-07,
        0.62155342102050781000, 3.32473711525130440e-07, 0.62337303161621094000, 6.17422578725226610e-08, 0.62519645690917969000,
        1.81088328592923450e-07, 0.62793731689453125000, 1.51907138131952650e-07, 0.62976884841918945000, 1.45422482854550170e-07,
        0.63160371780395508000, 1.73989360835447460e-07, 0.63344192504882813000, 1.30942033447158220e-07, 0.63620567321777344000,
        6.32214774319771320e-08, 0.63805246353149414000, 7.43358107609263670e-08, 0.63990259170532227000, 1.76951198127399670e-07,
        0.64175605773925781000, 3.51505838355915190e-07, 0.64454269409179688000, 2.34969616507881840e-08, 0.64640522003173828000,
        3.08717020729194160e-07, 0.64827060699462891000, 2.66479568021879930e-07, 0.65013980865478516000, 3.86682596209285870e-07,
        0.65201234817504883000, 2.05623294791264080e-07, 0.65388870239257813000, 1.13337006448265780e-07, 0.65670967102050781000,
        1.90746400810384850e-07, 0.65859460830688477000, 1.34506263688088150e-08, 0.66048336029052734000, 7.17589142772962000e-08,
        0.66237545013427734000, 3.79219956002368600e-07, 0.66427087783813477000, 4.72622485421169150e-07, 0.66617012023925781000,
        3.65670182864095200e-07, 0.66807317733764648000, 7.21451101499384280e-08, 0.66998004913330078000, 2.76320690561678240e-08,
        0.67284679412841797000, 2.82165706035616760e-07, 0.67476224899291992000, 3.98989742019840650e-07, 0.67668151855468750000,
        3.92246450307677540e-07, 0.67860460281372070000, 2.76159851543338650e-07, 0.68053150177001953000, 6.50363449710165520e-08,
        0.68246221542358398000, 2.50102503997607580e-07, 0.68439626693725586000, 3.68994245118910160e-07, 0.68633413314819336000,
        4.36268952312503260e-07, 0.68827581405639648000, 4.66568974938988130e-07, 0.69022130966186523000, 4.74622290241146250e-07,
        0.69217061996459961000
};

static __constant float __slgamma_ep_log_rcp_table_256[256] = {
    0.998046875000, 0.994140625000, 0.990234375000, 0.986328125000, 0.982910156250, 0.979003906250, 0.975097656250, 0.971679687500, 0.967773437500,
        0.964355468750, 0.960449218750, 0.957031250000, 0.953613281250, 0.949707031250, 0.946289062500, 0.942871093750, 0.939453125000,
        0.936035156250, 0.932617187500, 0.929199218750, 0.925781250000, 0.922363281250, 0.919433593750, 0.916015625000, 0.912597656250,
        0.909179687500, 0.906250000000, 0.902832031250, 0.899902343750, 0.896484375000, 0.893554687500, 0.890625000000, 0.887207031250,
        0.884277343750, 0.881347656250, 0.878417968750, 0.875000000000, 0.872070312500, 0.869140625000, 0.866210937500, 0.863281250000,
        0.860351562500, 0.857421875000, 0.854980468750, 0.852050781250, 0.849121093750, 0.846191406250, 0.843261718750, 0.840820312500,
        0.837890625000, 0.835449218750, 0.832519531250, 0.829589843750, 0.827148437500, 0.824707031250, 0.821777343750, 0.819335937500,
        0.816406250000, 0.813964843750, 0.811523437500, 0.809082031250, 0.806152343750, 0.803710937500, 0.801269531250, 0.798828125000,
        0.796386718750, 0.793945312500, 0.791503906250, 0.789062500000, 0.786621093750, 0.784179687500, 0.781738281250, 0.779296875000,
        0.776855468750, 0.774414062500, 0.772460937500, 0.770019531250, 0.767578125000, 0.765136718750, 0.763183593750, 0.760742187500,
        0.758300781250, 0.756347656250, 0.753906250000, 0.751953125000, 0.749511718750, 0.747558593750, 0.745117187500, 0.743164062500,
        0.740722656250, 0.738769531250, 0.736816406250, 0.734375000000, 0.732421875000, 0.730468750000, 0.728515625000, 0.726074218750,
        0.724121093750, 0.722167968750, 0.720214843750, 0.718261718750, 0.716308593750, 0.713867187500, 0.711914062500, 0.709960937500,
        0.708007812500, 0.706054687500, 0.704101562500, 0.702148437500, 0.700195312500, 0.698730468750, 0.696777343750, 0.694824218750,
        0.692871093750, 0.690917968750, 0.688964843750, 0.687011718750, 0.685546875000, 0.683593750000, 0.681640625000, 0.680175781250,
        0.678222656250, 0.676269531250, 0.674804687500, 0.672851562500, 0.670898437500, 0.669433593750, 0.667480468750, 0.666015625000,
        0.664062500000, 0.662597656250, 0.660644531250, 0.659179687500, 0.657226562500, 0.655761718750, 0.653808593750, 0.652343750000,
        0.650390625000, 0.648925781250, 0.647460937500, 0.645507812500, 0.644042968750, 0.642578125000, 0.640625000000, 0.639160156250,
        0.637695312500, 0.636230468750, 0.634277343750, 0.632812500000, 0.631347656250, 0.629882812500, 0.628417968750, 0.626464843750,
        0.625000000000, 0.623535156250, 0.622070312500, 0.620605468750, 0.619140625000, 0.617675781250, 0.616210937500, 0.614746093750,
        0.613281250000, 0.611816406250, 0.610351562500, 0.608886718750, 0.607421875000, 0.605957031250, 0.604492187500, 0.603027343750,
        0.601562500000, 0.600097656250, 0.598632812500, 0.597656250000, 0.596191406250, 0.594726562500, 0.593261718750, 0.591796875000,
        0.590332031250, 0.589355468750, 0.587890625000, 0.586425781250, 0.584960937500, 0.583984375000, 0.582519531250, 0.581054687500,
        0.580078125000, 0.578613281250, 0.577148437500, 0.576171875000, 0.574707031250, 0.573242187500, 0.572265625000, 0.570800781250,
        0.569335937500, 0.568359375000, 0.566894531250, 0.565917968750, 0.564453125000, 0.563476562500, 0.562011718750, 0.560546875000,
        0.559570312500, 0.558105468750, 0.557128906250, 0.556152343750, 0.554687500000, 0.553710937500, 0.552246093750, 0.551269531250,
        0.549804687500, 0.548828125000, 0.547363281250, 0.546386718750, 0.545410156250, 0.543945312500, 0.542968750000, 0.541992187500,
        0.540527343750, 0.539550781250, 0.538574218750, 0.537109375000, 0.536132812500, 0.535156250000, 0.533691406250, 0.532714843750,
        0.531738281250, 0.530761718750, 0.529296875000, 0.528320312500, 0.527343750000, 0.526367187500, 0.524902343750, 0.523925781250,
        0.522949218750, 0.521972656250, 0.520996093750, 0.520019531250, 0.518554687500, 0.517578125000, 0.516601562500, 0.515625000000,
        0.514648437500, 0.513671875000, 0.512695312500, 0.511718750000, 0.510253906250, 0.509277343750, 0.508300781250, 0.507324218750,
        0.506347656250, 0.505371093750, 0.504394531250, 0.503417968750, 0.502441406250, 0.501464843750, 0.500488281250
};

static __constant unsigned int __slgamma_ep_log_double_rcp_table_256[512] = {
    0x00000000, 0x3FEFF000,
    0x00000000, 0x3FEFD000,
    0x00000000, 0x3FEFB000,
    0x00000000, 0x3FEF9000,
    0x00000000, 0x3FEF7400,
    0x00000000, 0x3FEF5400,
    0x00000000, 0x3FEF3400,
    0x00000000, 0x3FEF1800,
    0x00000000, 0x3FEEF800,
    0x00000000, 0x3FEEDC00,
    0x00000000, 0x3FEEBC00,
    0x00000000, 0x3FEEA000,
    0x00000000, 0x3FEE8400,
    0x00000000, 0x3FEE6400,
    0x00000000, 0x3FEE4800,
    0x00000000, 0x3FEE2C00,
    0x00000000, 0x3FEE1000,
    0x00000000, 0x3FEDF400,
    0x00000000, 0x3FEDD800,
    0x00000000, 0x3FEDBC00,
    0x00000000, 0x3FEDA000,
    0x00000000, 0x3FED8400,
    0x00000000, 0x3FED6C00,
    0x00000000, 0x3FED5000,
    0x00000000, 0x3FED3400,
    0x00000000, 0x3FED1800,
    0x00000000, 0x3FED0000,
    0x00000000, 0x3FECE400,
    0x00000000, 0x3FECCC00,
    0x00000000, 0x3FECB000,
    0x00000000, 0x3FEC9800,
    0x00000000, 0x3FEC8000,
    0x00000000, 0x3FEC6400,
    0x00000000, 0x3FEC4C00,
    0x00000000, 0x3FEC3400,
    0x00000000, 0x3FEC1C00,
    0x00000000, 0x3FEC0000,
    0x00000000, 0x3FEBE800,
    0x00000000, 0x3FEBD000,
    0x00000000, 0x3FEBB800,
    0x00000000, 0x3FEBA000,
    0x00000000, 0x3FEB8800,
    0x00000000, 0x3FEB7000,
    0x00000000, 0x3FEB5C00,
    0x00000000, 0x3FEB4400,
    0x00000000, 0x3FEB2C00,
    0x00000000, 0x3FEB1400,
    0x00000000, 0x3FEAFC00,
    0x00000000, 0x3FEAE800,
    0x00000000, 0x3FEAD000,
    0x00000000, 0x3FEABC00,
    0x00000000, 0x3FEAA400,
    0x00000000, 0x3FEA8C00,
    0x00000000, 0x3FEA7800,
    0x00000000, 0x3FEA6400,
    0x00000000, 0x3FEA4C00,
    0x00000000, 0x3FEA3800,
    0x00000000, 0x3FEA2000,
    0x00000000, 0x3FEA0C00,
    0x00000000, 0x3FE9F800,
    0x00000000, 0x3FE9E400,
    0x00000000, 0x3FE9CC00,
    0x00000000, 0x3FE9B800,
    0x00000000, 0x3FE9A400,
    0x00000000, 0x3FE99000,
    0x00000000, 0x3FE97C00,
    0x00000000, 0x3FE96800,
    0x00000000, 0x3FE95400,
    0x00000000, 0x3FE94000,
    0x00000000, 0x3FE92C00,
    0x00000000, 0x3FE91800,
    0x00000000, 0x3FE90400,
    0x00000000, 0x3FE8F000,
    0x00000000, 0x3FE8DC00,
    0x00000000, 0x3FE8C800,
    0x00000000, 0x3FE8B800,
    0x00000000, 0x3FE8A400,
    0x00000000, 0x3FE89000,
    0x00000000, 0x3FE87C00,
    0x00000000, 0x3FE86C00,
    0x00000000, 0x3FE85800,
    0x00000000, 0x3FE84400,
    0x00000000, 0x3FE83400,
    0x00000000, 0x3FE82000,
    0x00000000, 0x3FE81000,
    0x00000000, 0x3FE7FC00,
    0x00000000, 0x3FE7EC00,
    0x00000000, 0x3FE7D800,
    0x00000000, 0x3FE7C800,
    0x00000000, 0x3FE7B400,
    0x00000000, 0x3FE7A400,
    0x00000000, 0x3FE79400,
    0x00000000, 0x3FE78000,
    0x00000000, 0x3FE77000,
    0x00000000, 0x3FE76000,
    0x00000000, 0x3FE75000,
    0x00000000, 0x3FE73C00,
    0x00000000, 0x3FE72C00,
    0x00000000, 0x3FE71C00,
    0x00000000, 0x3FE70C00,
    0x00000000, 0x3FE6FC00,
    0x00000000, 0x3FE6EC00,
    0x00000000, 0x3FE6D800,
    0x00000000, 0x3FE6C800,
    0x00000000, 0x3FE6B800,
    0x00000000, 0x3FE6A800,
    0x00000000, 0x3FE69800,
    0x00000000, 0x3FE68800,
    0x00000000, 0x3FE67800,
    0x00000000, 0x3FE66800,
    0x00000000, 0x3FE65C00,
    0x00000000, 0x3FE64C00,
    0x00000000, 0x3FE63C00,
    0x00000000, 0x3FE62C00,
    0x00000000, 0x3FE61C00,
    0x00000000, 0x3FE60C00,
    0x00000000, 0x3FE5FC00,
    0x00000000, 0x3FE5F000,
    0x00000000, 0x3FE5E000,
    0x00000000, 0x3FE5D000,
    0x00000000, 0x3FE5C400,
    0x00000000, 0x3FE5B400,
    0x00000000, 0x3FE5A400,
    0x00000000, 0x3FE59800,
    0x00000000, 0x3FE58800,
    0x00000000, 0x3FE57800,
    0x00000000, 0x3FE56C00,
    0x00000000, 0x3FE55C00,
    0x00000000, 0x3FE55000,
    0x00000000, 0x3FE54000,
    0x00000000, 0x3FE53400,
    0x00000000, 0x3FE52400,
    0x00000000, 0x3FE51800,
    0x00000000, 0x3FE50800,
    0x00000000, 0x3FE4FC00,
    0x00000000, 0x3FE4EC00,
    0x00000000, 0x3FE4E000,
    0x00000000, 0x3FE4D000,
    0x00000000, 0x3FE4C400,
    0x00000000, 0x3FE4B800,
    0x00000000, 0x3FE4A800,
    0x00000000, 0x3FE49C00,
    0x00000000, 0x3FE49000,
    0x00000000, 0x3FE48000,
    0x00000000, 0x3FE47400,
    0x00000000, 0x3FE46800,
    0x00000000, 0x3FE45C00,
    0x00000000, 0x3FE44C00,
    0x00000000, 0x3FE44000,
    0x00000000, 0x3FE43400,
    0x00000000, 0x3FE42800,
    0x00000000, 0x3FE41C00,
    0x00000000, 0x3FE40C00,
    0x00000000, 0x3FE40000,
    0x00000000, 0x3FE3F400,
    0x00000000, 0x3FE3E800,
    0x00000000, 0x3FE3DC00,
    0x00000000, 0x3FE3D000,
    0x00000000, 0x3FE3C400,
    0x00000000, 0x3FE3B800,
    0x00000000, 0x3FE3AC00,
    0x00000000, 0x3FE3A000,
    0x00000000, 0x3FE39400,
    0x00000000, 0x3FE38800,
    0x00000000, 0x3FE37C00,
    0x00000000, 0x3FE37000,
    0x00000000, 0x3FE36400,
    0x00000000, 0x3FE35800,
    0x00000000, 0x3FE34C00,
    0x00000000, 0x3FE34000,
    0x00000000, 0x3FE33400,
    0x00000000, 0x3FE32800,
    0x00000000, 0x3FE32000,
    0x00000000, 0x3FE31400,
    0x00000000, 0x3FE30800,
    0x00000000, 0x3FE2FC00,
    0x00000000, 0x3FE2F000,
    0x00000000, 0x3FE2E400,
    0x00000000, 0x3FE2DC00,
    0x00000000, 0x3FE2D000,
    0x00000000, 0x3FE2C400,
    0x00000000, 0x3FE2B800,
    0x00000000, 0x3FE2B000,
    0x00000000, 0x3FE2A400,
    0x00000000, 0x3FE29800,
    0x00000000, 0x3FE29000,
    0x00000000, 0x3FE28400,
    0x00000000, 0x3FE27800,
    0x00000000, 0x3FE27000,
    0x00000000, 0x3FE26400,
    0x00000000, 0x3FE25800,
    0x00000000, 0x3FE25000,
    0x00000000, 0x3FE24400,
    0x00000000, 0x3FE23800,
    0x00000000, 0x3FE23000,
    0x00000000, 0x3FE22400,
    0x00000000, 0x3FE21C00,
    0x00000000, 0x3FE21000,
    0x00000000, 0x3FE20800,
    0x00000000, 0x3FE1FC00,
    0x00000000, 0x3FE1F000,
    0x00000000, 0x3FE1E800,
    0x00000000, 0x3FE1DC00,
    0x00000000, 0x3FE1D400,
    0x00000000, 0x3FE1CC00,
    0x00000000, 0x3FE1C000,
    0x00000000, 0x3FE1B800,
    0x00000000, 0x3FE1AC00,
    0x00000000, 0x3FE1A400,
    0x00000000, 0x3FE19800,
    0x00000000, 0x3FE19000,
    0x00000000, 0x3FE18400,
    0x00000000, 0x3FE17C00,
    0x00000000, 0x3FE17400,
    0x00000000, 0x3FE16800,
    0x00000000, 0x3FE16000,
    0x00000000, 0x3FE15800,
    0x00000000, 0x3FE14C00,
    0x00000000, 0x3FE14400,
    0x00000000, 0x3FE13C00,
    0x00000000, 0x3FE13000,
    0x00000000, 0x3FE12800,
    0x00000000, 0x3FE12000,
    0x00000000, 0x3FE11400,
    0x00000000, 0x3FE10C00,
    0x00000000, 0x3FE10400,
    0x00000000, 0x3FE0FC00,
    0x00000000, 0x3FE0F000,
    0x00000000, 0x3FE0E800,
    0x00000000, 0x3FE0E000,
    0x00000000, 0x3FE0D800,
    0x00000000, 0x3FE0CC00,
    0x00000000, 0x3FE0C400,
    0x00000000, 0x3FE0BC00,
    0x00000000, 0x3FE0B400,
    0x00000000, 0x3FE0AC00,
    0x00000000, 0x3FE0A400,
    0x00000000, 0x3FE09800,
    0x00000000, 0x3FE09000,
    0x00000000, 0x3FE08800,
    0x00000000, 0x3FE08000,
    0x00000000, 0x3FE07800,
    0x00000000, 0x3FE07000,
    0x00000000, 0x3FE06800,
    0x00000000, 0x3FE06000,
    0x00000000, 0x3FE05400,
    0x00000000, 0x3FE04C00,
    0x00000000, 0x3FE04400,
    0x00000000, 0x3FE03C00,
    0x00000000, 0x3FE03400,
    0x00000000, 0x3FE02C00,
    0x00000000, 0x3FE02400,
    0x00000000, 0x3FE01C00,
    0x00000000, 0x3FE01400,
    0x00000000, 0x3FE00C00,
    0x00000000, 0x3FE00400
};

// approximation of (log(1+y)/y-1)/y on y=[-0.0022..0.0022] with err=.51e-18

static __constant unsigned int __slgamma_ep_log_P[] = {
    0x00000000, 0xbfe00000, 0x5554d0df, 0x3fd55555, 0xfffe169d, 0xbfcfffff, 0x4cdb6abc, 0x3fc999a2, 0x7bd1fcd4, 0xbfc5555f
};

// approximation of ((log(1+y)/y-1)/y on y=[-2^(-6)..2^(-6)] with err=.15e-21

static __constant unsigned int __slgamma_ep_log_Q1[] = {
    0x00000000, 0xbfe00000, 0x55555555, 0x3fd55555, 0xfffffffc, 0xbfcfffff, 0x999a2b21, 0x3fc99999, 0x55566ad6, 0xbfc55555, 0x78d1d116, 0x3fc24924,
        0xb94b8a57, 0xbfbfffff, 0x566ce20d, 0x3fbc756a, 0x03a0403e, 0xbfb99d9a
};

// approximation of ((log(1+y)/y-1)/y on y=[-2^(-13)..2^(-13)] with err=.28e-21

static __constant unsigned int __slgamma_ep_log_Q2[] = {
    0x00000000, 0xbfe00000, 0x55555555, 0x3fd55555, 0x03555556, 0xbfd00000, 0xa199b4b4, 0x3fc99999
};

static __constant unsigned int __slgamma_ep_log_LN2[] = {
    0x35793c76, 0x3dea39ef, 0xfee00000, 0x3fe62e42
};

static __constant unsigned int __slgamma_ep_log_TWO_55[] = { 0x00000000, 0x43600000 };  // 2^55

static __constant unsigned int __slgamma_ep_log_infs[] = { 0x00000000, 0x7ff00000, 0x00000000, 0xfff00000 };

//
// Positive args path of lgamma's data:
//

static __constant unsigned int __slgamma_ep__LM[] = {
    0x6356BE3F, 0x3FF762D8
};  // The point of local minimum on [1;2]

// [1,1.25)
static __constant unsigned int __slgamma_ep__C0[] = {
    0x21765550, 0x4004F394  // A0
        , 0xBC14D340, 0x3FAC8CDF, 0xFC0EE4DC, 0xBFE22092    // A8,A7
        , 0x7D9BF558, 0x4027CB00, 0xCA309876, 0xC02C6004    // A4,A3
        , 0xC3A02F10, 0x40048D48, 0xFD8B4838, 0xC01B63D2    // A6,A5
        , 0x5B1371AE, 0x40288FCC, 0xF1F3E423, 0xC01F4732    // A2,A1
};

// [1.25,1.5)
static __constant unsigned int __slgamma_ep__C1[] = {
    0xBCC38A42, 0xBFBF19B9  // A0
        , 0x35A6171A, 0x3F838E0D, 0xD61313B7, 0xBF831BBB    // A8,A7
        , 0x196425D0, 0x3FB08B40, 0xA53EB830, 0xBFC2E427    // A4,A3
        , 0xDC20D6C3, 0x3F9285DD, 0x9C223044, 0xBFA0C90C    // A6,A5
        , 0xC8F5287C, 0x3FDEF72B, 0xAEBC1DFC, 0x3D890B3D    // A2,A1
};

// [1.5,1.75)
static __constant unsigned int __slgamma_ep__C2[] = {
    0xF9DFA0CC, 0x4001DB08  // A0
        , 0xEB31047F, 0x3F65D5A7, 0x9BFA7FDE, 0xBFA44EAC    // A8,A7
        , 0xE7A663D8, 0x40051FEF, 0xE00A2522, 0xC012A5CF    // A4,A3
        , 0x3AB00E08, 0x3FD0E158, 0x95883BA5, 0xBFF084AF    // A6,A5
        , 0x877AE0A2, 0x40185982, 0xB73B57B7, 0xC015F83D    // A2,A1
};

// [1.75,2.0)
static __constant unsigned int __slgamma_ep__C3[] = {
    0x38D6CF0A, 0x4000A0CB  // A0
        , 0x032EB39A, 0x3F4A9222, 0x87EEA5A3, 0xBF8CBC95    // A8,A7
        , 0x0783BE49, 0x3FF79540, 0x418B8A25, 0xC00851BC    // A4,A3
        , 0x783E8C5B, 0x3FBBC992, 0x65E89B29, 0xBFDFA67E    // A6,A5
        , 0xF02FAF88, 0x4012B408, 0xE7CB0C39, 0xC013284C    // A2,A1
};

// [2;4)
static __constant unsigned int __slgamma_ep__C4[] = {
    0x38B9355F, 0xBEB2CC7A, 0x1833BF4C, 0x3F035F2D  // A10,A9
        , 0x7FD27785, 0xBFF51BAA, 0x5B6CDEFF, 0x3FFC9D5D    // A2,A1
        , 0xF9CB46C7, 0xBF421676, 0xFA1436C6, 0x3F7437F2    // A8,A7
        , 0x1DE592FE, 0xBFD7A704, 0xFEE8BD29, 0x3FE9F107    // A4,A3
        , 0x9FB224AB, 0xBF9E1C28, 0x445C9460, 0x3FBF7422    // A6,A5
        , 0xD66F8D8A, 0xBFF01E76    // A0
};

// [4; 2^13)

static __constant unsigned int __slgamma_ep__A[] = {
    0x40800000  // 00:    4.0
        , 0x41000000    // 01:    8.0
        , 0x41800000    // 02:   16.0
        , 0x42000000    // 03:   32.0
        , 0x42800000    // 04:   64.0
        , 0x43000000    // 05:  128.0
        , 0x43800000    // 06:  256.0
        , 0x44000000    // 07:  512.0
        , 0x44800000    // 08: 1024.0
        , 0x45000000    // 09: 2048.0
        , 0x45800000    // 10: 4096.0
};

/* [4; 2^13) */

static __constant unsigned int __slgamma_ep__B[] = {
    0x3E800000  // 00: 1.0/   4.0
        , 0x3E000000    // 01: 1.0/   8.0
        , 0x3D800000    // 02: 1.0/  16.0
        , 0x3D000000    // 03: 1.0/  32.0
        , 0x3C800000    // 04: 1.0/  64.0
        , 0x3C000000    // 05: 1.0/ 128.0
        , 0x3B800000    // 06: 1.0/ 256.0
        , 0x3B000000    // 07: 1.0/ 512.0
        , 0x3A800000    // 08: 1.0/1024.0
        , 0x3A000000    // 09: 1.0/2048.0
        , 0x39800000    // 10: 1.0/4096.0
};

// [4; 2^13)

static __constant unsigned int __slgamma_ep__C5_0[] = {
// 00: [4;8)
    0x9000EB5C, 0x3FCB8CC6, 0xA0C2C641, 0xBFD41997  // A6,A5
        , 0xFA0EA462, 0x3FFCAB0B    // A0
// 01: [8;16)
        , 0xDE0A364C, 0x3FD51EE4, 0x98A16E4B, 0xBFE00D7F    // A6,A5
        , 0xF327E9E4, 0x40210CE1    // A0
// 02: [16;32)
        , 0x6742D252, 0x3FE24F60, 0xD12574EC, 0xBFEC81D7    // A6,A5
        , 0xA63A9C27, 0x403BE636    // A0
// 03: [32;64)
        , 0x9DD542B4, 0x3FF1029A, 0x209D3B25, 0xBFFAD37C    // A6,A5
        , 0xFD9BE7EA, 0x405385E6    // A0
// 04: [64;128)
        , 0x7D26B523, 0x400062D9, 0x529FF023, 0xC00A03E1    // A6,A5
        , 0x51E566CE, 0x4069204C    // A0
// 05: [128;256)
        , 0xB38FD501, 0x40101476, 0xB387C0FC, 0xC0199DE7    // A6,A5
        , 0xEC83D759, 0x407EB8DA    // A0
// 06: [256;512)
        , 0x8D65125A, 0x401FDB00, 0x6E665581, 0xC0296B50    // A6,A5
        , 0x3107EF66, 0x409226D9    // A0
// 07: [512;1024)
        , 0xAF3E7B2D, 0x402FB3EA, 0x42AD8E0D, 0xC0395211    // A6,A5
        , 0xF072792E, 0x40A4EFA4    // A0
// 08: [1024;2048)
        , 0xC66B2563, 0x403FA024, 0xF250E691, 0xC0494569    // A6,A5
        , 0xC9235BB8, 0x40B7B747    // A0
// 09: [2048;4096)
        , 0xD6DA512C, 0x404F9607, 0x2EDDB4BC, 0xC0593F0B    // A6,A5
        , 0xC5F16DE2, 0x40CA7E29    // A0
// 10: [4096;8192)
        , 0xF613D98D, 0x405F90C5, 0x30E50AAF, 0xC0693BD1    // A6,A5
        , 0x238B190C, 0x40DD4495    // A0
};

// [4; 2^13)
static __constant unsigned int __slgamma_ep__C5[] = {
// 00: [4;8)
    0x8451C0CD, 0x3F6BBBD6, 0x272A16F7, 0xBF966EC3  // A10,A9
        , 0xA39AD769, 0x40022A24, 0xDF49C8C5, 0x4014190E    // A2,A1
        , 0x016EE241, 0x3FB130FD, 0x6E635248, 0xBFC151B4    // A8,A7
        , 0x1965B5FE, 0x3FDE8F61, 0xEB265E3D, 0xBFEB5110    // A4,A3
// 01: [8;16)
        , 0x3508626A, 0x3F736EF9, 0xADF58AF1, 0xBF9FE5DB    // A10,A9
        , 0xC5192058, 0x40110A9F, 0xA6F96B29, 0x40302008    // A2,A1
        , 0x0CE1E4B5, 0x3FB8E74E, 0x78873656, 0xBFC9B5DA    // A8,A7
        , 0xF10022DC, 0x3FE99D0D, 0x388F9484, 0xBFF829C0    // A4,A3
// 02: [16;32)
        , 0x6D7E9269, 0x3F7FFF9D, 0x249AEDB1, 0xBFAA780A    // A10,A9
        , 0x07AEA080, 0x402082A8, 0x68408013, 0x4045ED98    // A2,A1
        , 0x4C2F99B7, 0x3FC4E1E5, 0x6FFF1490, 0xBFD5DE2D    // A8,A7
        , 0x9584AE87, 0x3FF75FC8, 0xDD886CAE, 0xC006B4BA    // A4,A3
// 03: [32;64)
        , 0x75841A5F, 0x3F8CE543, 0xCFFA1BE2, 0xBFB801AB    // A10,A9
        , 0xB1815BDA, 0x403040A8, 0x17D24B7A, 0x405B99A9    // A2,A1
        , 0x81BFFA03, 0x3FD30CAB, 0x61ECF48B, 0xBFE41AEF    // A8,A7
        , 0x136BEC43, 0x400650CC, 0x46E8292B, 0xC0160220    // A4,A3
// 04: [64;128)
        , 0x22CAA8B8, 0x3F9B69BD, 0x75B7A213, 0xBFC6D488    // A10,A9
        , 0xCCAA2F6D, 0x40402028, 0xEB3CBE0F, 0x40709AAC    // A2,A1
        , 0x5924761E, 0x3FE22C6A, 0xF224523D, 0xBFF342F5    // A8,A7
        , 0x5CCA331F, 0x4015CD40, 0x0482C769, 0xC025AAD1    // A4,A3
// 05: [128;256)
        , 0xD0E40D06, 0x3FAAAD9C, 0x505D80CB, 0xBFD63FC8    // A10,A9
        , 0xD56C2648, 0x40501008, 0x4B0F4376, 0x40836479    // A2,A1
        , 0x26E00284, 0x3FF1BE01, 0xF6F7F7CA, 0xC002D8E3    // A8,A7
        , 0x7E95D860, 0x40258C75, 0xFD398011, 0xC0357FA8    // A4,A3
// 06: [256;512)
        , 0x59D49FEB, 0x3FBA4DAC, 0xD1C43A77, 0xBFE5F476    // A10,A9
        , 0xD890C7C6, 0x40600800, 0xAAEC8EF0, 0x40962C42    // A2,A1
        , 0xECF19B89, 0x40018680, 0x96FB7BA4, 0xC012A3EB    // A8,A7
        , 0xDD3B60F9, 0x40356C4C, 0xBF18F440, 0xC0456A34    // A4,A3
// 07: [512;1024)
        , 0xF6225A5A, 0x3FCA1B54, 0xBA10E048, 0xBFF5CD67    // A10,A9
        , 0xD94C58C2, 0x407003FE, 0x4ACBCD22, 0x40A8F30B    // A2,A1
        , 0x5EB66D8C, 0x40116A13, 0x1CED527E, 0xC022891B    // A8,A7
        , 0x17FDD8BC, 0x40455C46, 0x729E59C4, 0xC0555F82    // A4,A3
// 08: [1024;2048)
        , 0x095C6EC9, 0x3FD9FFF9, 0xB25D76C9, 0xC005B88C    // A10,A9
        , 0x58FA734D, 0x408001FE, 0xBAABB0F3, 0x40BBB953    // A2,A1
        , 0x9FEB5D87, 0x40215B2F, 0x9DEA5058, 0xC0327B53    // A8,A7
        , 0xB3E8D64D, 0x40555444, 0x26F9FC8A, 0xC0655A2B    // A4,A3
// 09: [2048;4096)
        , 0xA1C3D6B1, 0x3FE9F065, 0xFAE8D78D, 0xC015ACF6    // A10,A9
        , 0x383DD2B7, 0x409000FE, 0x1E8BCB8B, 0x40CE7F5C    // A2,A1
        , 0xE5DB2EBE, 0x40315324, 0x4EF70D18, 0xC0427419    // A8,A7
        , 0x53FF2207, 0x40655043, 0xE1BFE7B6, 0xC075577F    // A4,A3
// 10: [4096;8192)
        , 0xC6B1C70D, 0x3FF9E6FB, 0xAF76F85D, 0xC025A62D    // A10,A9
        , 0x2F61EBE8, 0x40A0007E, 0x3FB5F6C3, 0x40E0A2A2    // A2,A1
        , 0xC0A0141A, 0x40414E9B, 0xF2B69D43, 0xC0527030    // A8,A7
        , 0x7717B45B, 0x40754E41, 0x447258E5, 0xC085562A    // A4,A3
};

//
// Main path of lgamma's data:
//

static __constant float __slgamma_ep__TWO_23H[2] = { 12582912.0, -12582912.0 };

// ln(sqrt(2*Pi)) = 0.9189385332046727417803297364056176398618

static __constant unsigned int __slgamma_ep__LN_SQRT_TWO_PI[] = { 0xc864beb5, 0x3fed67f1 };

// Maximal positive number

static __constant int __slgamma_ep__PBIG[] = { 0x7f7fffff, 0x7f7fffff };

// polynomial approximation of ln(sin(Pi*r)/(Pi*r)), |r| <= 0.5

static __constant unsigned int __slgamma_ep__S16[] = { 0xA486E820, 0xBFD58731 };

static __constant unsigned int __slgamma_ep__S14[] = { 0xC28E15A9, 0xBFA4452C };

static __constant unsigned int __slgamma_ep__S08[] = { 0xE1B86C4F, 0xBFD013F6 };

static __constant unsigned int __slgamma_ep__S06[] = { 0x9F7A341F, 0xBFD5B3F1 };

static __constant unsigned int __slgamma_ep__S12[] = { 0x5252E778, 0xBFC86A0D };

static __constant unsigned int __slgamma_ep__S10[] = { 0xC9EE284B, 0xBFC93E08 };

static __constant unsigned int __slgamma_ep__S04[] = { 0x555C9EDD, 0xBFE15132 };

static __constant unsigned int __slgamma_ep__S02[] = { 0x62480E35, 0xBFFA51A6 };

// Left root polynomials.

static __constant unsigned int __slgamma_ep__LRP[] = {
// near -2.7476826467274126919
    0xC31314FF, 0xC034185A, 0x3C28DFE3, 0x4023267F  // R3,R2
        , 0xA904B194, 0xBFFEA12D, 0x30BA7689, 0x3CA8FB85    // R1,R0
// near -3.9552942848585979085
        , 0x9E70C888, 0xC0AD2535, 0xAEA1B8C6, 0x406F76DE    // R3,R2
        , 0x966C5644, 0xC034B99D, 0x36980B58, 0xBCBDDC03    // R1,R0
};

// Right root polynomials.

static __constant unsigned int __slgamma_ep__RRP[] = {
// near -2.4570247382208005860
    0x058D9592, 0x3FF694A6, 0xB003A92B, 0x40136EEB  // R3,R2
        , 0x66AF5360, 0x3FF83FE9, 0x6D1FE86D, 0x3C90323B    // R1,R0
// near -3.1435808883499798405
        , 0x1268DA38, 0x405C1137, 0x977D2C23, 0x4039D4D2    // R3,R2
        , 0x5F2FAC62, 0x401F20A6, 0xE3AE7A62, 0x3CDE9605    // R1,R0
};

// Left root and it's bounds.

static __constant unsigned int __slgamma_ep__LRIB[] = {
    0xA9328A1D, 0xC005FB43, 0x0A1BD901, 0xC005FB41  // -2.7476826467274126919
        , 0x6B0527E5, 0xC005FB3E, 0xD0D6F455, 0xC00FA47B, 0x547C2FE5, 0xC00FA471    // -3.9552942848585979085
    , 0x80000000, 0xC00FA45D
};

// Right root and it's bounds.

static __constant unsigned int __slgamma_ep__RRIB[] = {
    0x3517A988, 0xC003A7FF, 0x9600F86C, 0xC003A7FC  // -2.4570247382208005860
        , 0xF6EA4750, 0xC003A7F9, 0x5BB50ACB, 0xC0092610, 0xBC9E59AF, 0xC009260D    // -3.1435808883499798405
    , 0x1D87A893, 0xC009260B
};

//! ===========================================================================
//! @brief 64-bit natural logarithm value computation routine usign LUT
//!
//! @param[in] arg     Argument
//! @return            Returns 64-bit natural logarithm
//! ===========================================================================
__attribute__((always_inline))
static inline double __slgamma_ep_own_log_lut_fp64 (double x)
{
    int n = 0, i = 0;
    unsigned ix = 0x0u;
    __constant double *table;
    double xl = 0.0, y = 0.0, yl = 0.0, r = 0.0, s = 0.0, t = 0.0, result = 0.0;

    ix = ((int *) &x)[1];
    if (ix < 0x7ff00000u)
    {   // finite positive x
        if ((ix - 0x3fef8000u) < (0x3ff04000u - 0x3fef8000u))
        {   // |x-1| < 2^(-6)
            if ((ix - 0x3fefff00u) < (0x3ff00080u - 0x3fefff00u))
            {   // |x-1| < 2^(-13)
                if (((ix - 0x3ff00000u) | ((int *) &x)[0]) == 0)
                {   // x == 1.0
                    return ((__constant float *) __slgamma_ep_log_zeros)[0];
                }
                else
                {   // 0 < |x-1| < 2^(-13)
                    x += ((__constant float *) __slgamma_ep_log_ones)[1];
                    y = x * x;
                    result =
                        ((((__constant double *) __slgamma_ep_log_Q2)[3] * y + ((__constant double *) __slgamma_ep_log_Q2)[1]) * y +
                         (((__constant double *) __slgamma_ep_log_Q2)[2] * y + ((__constant double *) __slgamma_ep_log_Q2)[0]) * x) * x + x;
                    return result;
                }
            }   // if (ix-0x3fefff00 < 0x3ff00080-0x3fefff00)
            else
            {   // 2^(-13) <= |x-1| <= 2^(-6)
                x += ((__constant float *) __slgamma_ep_log_ones)[1];
                s = x;
                xl = x;
                ((int *) &x)[0] = 0;
                xl -= x;
                t = s * s;
                yl = y = x * x;
                ((int *) &y)[0] = 0;
                yl -= y;
                yl += xl * x + xl * (x + xl);
                t = ((((((__constant double *) __slgamma_ep_log_Q1)[7] * t + ((__constant double *) __slgamma_ep_log_Q1)[5]) * t +
                       ((__constant double *) __slgamma_ep_log_Q1)[3]) * t + ((__constant double *) __slgamma_ep_log_Q1)[1]) * s +
                     (((((__constant double *) __slgamma_ep_log_Q1)[8] * t + ((__constant double *) __slgamma_ep_log_Q1)[6]) * t +
                       ((__constant double *) __slgamma_ep_log_Q1)[4]) * t + ((__constant double *) __slgamma_ep_log_Q1)[2]) * t) * t;
                xl += t;
                xl += ((__constant double *) __slgamma_ep_log_Q1)[0] * yl;
                x += ((__constant double *) __slgamma_ep_log_Q1)[0] * y;
                result = (x + xl);
                return result;
            }   // else if (ix-0x3fefff00 < 0x3ff00080-0x3fefff00)
        }   // if (ix-0x3fef8000 < 0x3ff04000-0x3fef8000)
        else
        {   // |x-1| > 2^(-6)
            n = (ix >> 20) - 0x3FF;
            ((int *) &x)[1] &= ~0xfff00000u;
            if (ix < 0x00100000u)
            {   // handle subnormals
                if ((ix | ((int *) &x)[0]) == 0)
                {   // x == +0
                    result = (((__constant float *) __slgamma_ep_log_ones)[(1)] / ((__constant float *) __slgamma_ep_log_zeros)[0]);    // raise div-by-_VSTATIC(zero), return -INF
                    return result;
                }
                x *= (*(__constant double *) __slgamma_ep_log_TWO_55);
                ix = ((int *) &x)[1];
                n = (ix >> 20) - (55 + 0x3FF);
            }   // if (ix < 0x00100000)
            i = (ix >> 12) & 0xffu;
            ((int *) &x)[1] |= 0x3ff00000u;
            r = __slgamma_ep_log_rcp_table_256[i];
            xl = x;
            ((int *) &x)[0] = 0;
            xl -= x;    // break x fraction into high(x) and low(xl) parts
            x *= r;
            xl *= r;
            x += ((__constant float *) __slgamma_ep_log_ones)[1];   // x*r-1 == (hi*r-1) + lo*r, for best precision
            s = (x + xl);
            y = s * s;
            table = &__slgamma_ep_log_table_256[2 * i]; // T_lo,T_hi
            t = ((((__constant double *) __slgamma_ep_log_P)[4] * y + ((__constant double *) __slgamma_ep_log_P)[2]) * y +
                 ((__constant double *) __slgamma_ep_log_P)[0]) * y + (((__constant double *) __slgamma_ep_log_P)[3] * y +
                                                                       ((__constant double *) __slgamma_ep_log_P)[1]) * s * y;
            xl += t;
            t = (table[0] + (double) n * ((__constant double *) __slgamma_ep_log_LN2)[0]);
            xl += t;
            t = (table[1] + (double) n * ((__constant double *) __slgamma_ep_log_LN2)[1]);
            x += t;
            result = (x + xl);
            return result;
        }   // else if (ix-0x3fef8000 < 0x3ff04000-0x3fef8000)
    }   // if (ix < 0x7ff00000)
    else
    {   // NaN, INF, negative x
        ix &= ~0x80000000u;
        if ((ix > 0x7ff00000u) || ((ix == 0x7ff00000u) && (((int *) &x)[0] != 0)))
        {   // NaN
            return x * ((__constant float *) __slgamma_ep_log_ones)[0]; // raise invalid on SNaN
        }
        else if (((int *) &x)[1] & 0x80000000u)
        {   // negative x
            if ((ix | ((int *) &x)[0]) == 0)
            {   // x == -0
                result = (((__constant float *) __slgamma_ep_log_ones)[(1)] / ((__constant float *) __slgamma_ep_log_zeros)[0]);    // raise div-by-_VSTATIC(zero), return -INF
                return result;
            }
            else
            {   // x < -0
                result = (((__constant double *) __slgamma_ep_log_infs)[0] * ((__constant float *) __slgamma_ep_log_zeros)[0]); // raise invalid, return QNaN
                return result;
            }
        }   // else if (LOG_I64_HI(x) & 0x80000000)
        else
        {   // +INF
            return x;
        }
    }   // else if (ix < 0x7ff00000)
}   // static inline double _VSTATIC(own_log_lut_fp64) (double x)

//! ===========================================================================
//! @brief 32-bit nearbyint computation routine
//!
//! @param[in] sA      Argument
//! @return            Returns 32-bit nearbyint
//! ===========================================================================
__attribute__((always_inline))
static inline float __slgamma_ep_own_nearbyint_fp32 (float sA)
{
    float _rnd_s2p23 = 0.0f;
    float _rnd_sSignMask = 0.0f;
    float _rnd_sSign = 0.0f;
    float _rnd_sAbsArg = 0.0f;
    float _rnd_sRes_ub = 0.0f;
    float _rnd_sRange = 0.0f;
    unsigned int _rnd_i2p23 = 0x4b000000u;
    unsigned int _rnd_iSignMask = 0x80000000u;
    _rnd_s2p23 = (*((float *) &(_rnd_i2p23)));
    _rnd_sSignMask = (*((float *) &(_rnd_iSignMask)));
    (*((unsigned int *) &(_rnd_sSign))) = ((*((unsigned int *) &(sA))) & (*((unsigned int *) &(_rnd_sSignMask))));
    (*((unsigned int *) &(_rnd_sAbsArg))) = (~((*((unsigned int *) &(_rnd_sSignMask)))) & (*((unsigned int *) &(sA))));
    (*((unsigned int *) &(_rnd_sRange))) = ((unsigned int) (-(int) (_rnd_sAbsArg > _rnd_s2p23)));
    _rnd_sRes_ub = (_rnd_sAbsArg + _rnd_s2p23);
    _rnd_sRes_ub = (_rnd_sRes_ub - _rnd_s2p23);
    (*((unsigned int *) &(_rnd_sRes_ub))) = ((*((unsigned int *) &(_rnd_sRes_ub))) | (*((unsigned int *) &(_rnd_sSign))));
    (*((unsigned int *) &(_rnd_sRes_ub))) =
        (((~(*((unsigned int *) &(_rnd_sRange)))) & (*((unsigned int *) &(_rnd_sRes_ub)))) |
         ((*((unsigned int *) &(_rnd_sRange))) & (*((unsigned int *) &(sA)))));
    return _rnd_sRes_ub;
}   // static inline float _VSTATIC(own_nearbyint_fp32)( float sA )

//! ===========================================================================
//! @brief 32-bit ceil computation routine
//!
//! @param[in] sA      Argument
//! @return            Returns 32-bit ceil
//! ===========================================================================
__attribute__((always_inline))
static inline float __slgamma_ep_own_ceilf_fp32 (float sA)
{
    float _rnd_s2p23 = 0.0f;
    float _rnd_sSignMask = 0.0f;
    float _rnd_sSign = 0.0f;
    float _rnd_sIsGreater = 0.0f;
    float _rnd_sOne = 0.0f;
    float _rnd_sAddOne = 0.0f;
    float _rnd_sAbsArg = 0.0f;
    float _rnd_sRes_ub = 0.0f;
    float _rnd_sRange = 0.0f;
    unsigned int _rnd_i2p23 = 0x4b000000u;
    unsigned int _rnd_iSignMask = 0x80000000u;
    unsigned int _rnd_iOne = 0x3f800000u;
    _rnd_sSignMask = (*((float *) &(_rnd_iSignMask)));
    (*((unsigned int *) &(_rnd_sSign))) = ((*((unsigned int *) &(sA))) & (*((unsigned int *) &(_rnd_sSignMask))));
    (*((unsigned int *) &(_rnd_sAbsArg))) = (~((*((unsigned int *) &(_rnd_sSignMask)))) & (*((unsigned int *) &(sA))));
    _rnd_s2p23 = (*((float *) &(_rnd_i2p23)));
    (*((unsigned int *) &(_rnd_sRange))) = ((unsigned int) (-(signed int) (_rnd_sAbsArg > _rnd_s2p23)));
    _rnd_sRes_ub = (_rnd_sAbsArg + _rnd_s2p23);
    _rnd_sRes_ub = (_rnd_sRes_ub - _rnd_s2p23);
    (*((unsigned int *) &(_rnd_sRes_ub))) = ((*((unsigned int *) &(_rnd_sRes_ub))) | (*((unsigned int *) &(_rnd_sSign))));
    (*((unsigned int *) &(_rnd_sIsGreater))) = ((unsigned int) (-(signed int) (sA > _rnd_sRes_ub)));
    _rnd_sOne = (*((float *) &(_rnd_iOne)));
    (*((unsigned int *) &(_rnd_sAddOne))) = ((*((unsigned int *) &(_rnd_sOne))) & (*((unsigned int *) &(_rnd_sIsGreater))));
    _rnd_sRes_ub = _rnd_sRes_ub + _rnd_sAddOne;
    (*((unsigned int *) &(_rnd_sRes_ub))) =
        (((~(*((unsigned int *) &(_rnd_sRange)))) & (*((unsigned int *) &(_rnd_sRes_ub)))) |
         ((*((unsigned int *) &(_rnd_sRange))) & (*((unsigned int *) &(sA)))));
    return _rnd_sRes_ub;
}   // static inline float _VSTATIC(own_ceilf_fp32)( float sA )

//! ===========================================================================
//! @brief 32-bit Gergo Nemes fast lgamma approximation
//!
//! @param[in] arg     Argument
//! @return            Returns 32-bit lgamma
//! ===========================================================================
__attribute__((always_inline))
static inline float __slgamma_ep_own_lgamma_fast_fp32 (float arg)
{

    unsigned int __slgamma_ep_own_log2pif = 0x3feb3f8eu;
    float result = 0.5f * ((*(float *) &(__slgamma_ep_own_log2pif)) - SPIRV_OCL_BUILTIN(log, _f32, ) (arg));
    result = result + (arg * (SPIRV_OCL_BUILTIN(log, _f32, ) (arg + (1.0f / ((12.0f * arg) - (1.0f / (10.0f * arg))))) - 1.0f));
    return result;
}   // static inline float _VSTATIC(own_lgamma_fast_fp32) (float arg)

//! ===========================================================================
//! @brief 64-bit Gergo Nemes fast lgamma approximation
//!
//! @param[in] arg     Argument
//! @return            Returns 64-bit lgamma
//! ===========================================================================
__attribute__((always_inline))
static inline double __slgamma_ep_own_lgamma_fast_fp64 (double arg)
{

    unsigned int __slgamma_ep_own_log2pi[] = { 0xc864beb5u, 0x3ffd67f1u };
    double result = 0.5 * ((*(double *) __slgamma_ep_own_log2pi) - __slgamma_ep_own_log_lut_fp64 (arg));
    result = result + (arg * (__slgamma_ep_own_log_lut_fp64 (arg + (1.0 / ((12.0 * arg) - (1.0 / (10.0 * arg))))) - 1.0));
    return result;
}   // static inline double _VSTATIC(own_lgamma_fast_fp64) (double arg)

//! ===========================================================================
//! @brief 64-bit lgamma approximation for positive arguments in [0.0; 2^13)
//!
//! @param[in] arg     Argument
//! @return            Returns 64-bit lgamma
//! ===========================================================================
__attribute__((always_inline))
static inline double __slgamma_ep_own_lgamma_pos_fp64 (double arg)
{
    double x = 0.0, result = 0.0, y = 0.0, p = 0.0, y2 = 0.0, lx = 0.0;
    unsigned int ix = 0;
    int i = 0;

    if (arg < 1.0)
    {
        x = arg + 1.0;
        lx = __slgamma_ep_own_log_lut_fp64 (arg);
    }
    else
    {
        x = arg;
        lx = 0.0;
    }

    ix = ((((_iml_v2_dp_union_t *) & x)->dwords.hi_dword));

    if ((x == 1.0) || (x == 2.0))
    {
        // lgamma(1) = +0
        // lgamma(2) = +0
        result = 0.0;
    }
    else if (x >= 4.0)  // 4 <= x < 2^13:
    {

        result = __slgamma_ep_own_lgamma_fast_fp64 (x);
    }   // else if ( x >= 4.0 ) // 4 <= x < 2^13:
    else if (x > 2.0)
    {
        //
        // 2 < x < 4:
        // --------------
        // ln(GAMMA(x)) ~ (x-2)*P10(x)
        //
        y2 = x * x;
        p = ((((((__constant double *) __slgamma_ep__C4)[1] * y2
                + ((__constant double *) __slgamma_ep__C4)[5]) * y2
               + ((__constant double *) __slgamma_ep__C4)[9]) * y2
              + ((__constant double *) __slgamma_ep__C4)[7]) * y2 + ((__constant double *) __slgamma_ep__C4)[3]) * x;
        result = ((((((__constant double *) __slgamma_ep__C4)[0] * y2
                     + ((__constant double *) __slgamma_ep__C4)[4]) * y2
                    + ((__constant double *) __slgamma_ep__C4)[8]) * y2
                   + ((__constant double *) __slgamma_ep__C4)[6]) * y2
                  + ((__constant double *) __slgamma_ep__C4)[2]) * y2 + ((__constant double *) __slgamma_ep__C4)[10];
        result = result + p;
        p = x - 2.0;
        result = result * p;
    }   // else if ( x > 2.0 )
    else if (x >= 1.75)
    {
        //
        // 1.75 <= x < 2:
        // -----------------
        // ln(GAMMA(x)) ~ P8(x)
        //
        y2 = x * x;
        p = (((((__constant double *) __slgamma_ep__C3)[2] * y2
               + ((__constant double *) __slgamma_ep__C3)[6]) * y2
              + ((__constant double *) __slgamma_ep__C3)[4]) * y2 + ((__constant double *) __slgamma_ep__C3)[8]) * x;
        result = (((((__constant double *) __slgamma_ep__C3)[1] * y2
                    + ((__constant double *) __slgamma_ep__C3)[5]) * y2
                   + ((__constant double *) __slgamma_ep__C3)[3]) * y2
                  + ((__constant double *) __slgamma_ep__C3)[7]) * y2 + ((__constant double *) __slgamma_ep__C3)[0];
        result = result + p;
    }   // else if ( x >= 1.75 )
    else if (x >= 1.5)
    {
        //
        // 1.5 <= x < 1.75:
        // -----------------
        // ln(GAMMA(x)) ~ P8(x)
        //
        y2 = x * x;
        p = (((((__constant double *) __slgamma_ep__C2)[2] * y2
               + ((__constant double *) __slgamma_ep__C2)[6]) * y2
              + ((__constant double *) __slgamma_ep__C2)[4]) * y2 + ((__constant double *) __slgamma_ep__C2)[8]) * x;
        result = (((((__constant double *) __slgamma_ep__C2)[1] * y2
                    + ((__constant double *) __slgamma_ep__C2)[5]) * y2
                   + ((__constant double *) __slgamma_ep__C2)[3]) * y2
                  + ((__constant double *) __slgamma_ep__C2)[7]) * y2 + ((__constant double *) __slgamma_ep__C2)[0];
        result = result + p;
    }   // else if ( x >= 1.5 )
    else if (x >= 1.25)
    {
        //
        // 1.25 <= x < 1.5:
        // -----------------
        // ln(GAMMA(x)) ~ ln(GAMMA(x0))+(x-x0)*P7(x-x0),
        // where x0 - point of local minimum on [1;2]
        // rounded to nearest double precision number.
        //
        y = x - (*(__constant double *) __slgamma_ep__LM);
        y2 = y * y;
        p = (((((__constant double *) __slgamma_ep__C1)[2] * y2
               + ((__constant double *) __slgamma_ep__C1)[6]) * y2
              + ((__constant double *) __slgamma_ep__C1)[4]) * y2 + ((__constant double *) __slgamma_ep__C1)[8]) * y;
        result = (((((__constant double *) __slgamma_ep__C1)[1] * y2
                    + ((__constant double *) __slgamma_ep__C1)[5]) * y2
                   + ((__constant double *) __slgamma_ep__C1)[3]) * y2
                  + ((__constant double *) __slgamma_ep__C1)[7]) * y2 + ((__constant double *) __slgamma_ep__C1)[0];
        result = result + p;
    }   // else if ( x >= 1.25 )
    else    // if ( x >= 1.0 )
    {
        //
        // 1 <= x < 1.25:
        // -----------------
        // ln(GAMMA(x)) ~ P8(x)
        //
        y2 = x * x;
        p = (((((__constant double *) __slgamma_ep__C0)[2] * y2
               + ((__constant double *) __slgamma_ep__C0)[6]) * y2
              + ((__constant double *) __slgamma_ep__C0)[4]) * y2 + ((__constant double *) __slgamma_ep__C0)[8]) * x;
        result = (((((__constant double *) __slgamma_ep__C0)[1] * y2
                    + ((__constant double *) __slgamma_ep__C0)[5]) * y2
                   + ((__constant double *) __slgamma_ep__C0)[3]) * y2
                  + ((__constant double *) __slgamma_ep__C0)[7]) * y2 + ((__constant double *) __slgamma_ep__C0)[0];
        result = result + p;
    }   // else // if ( x >= 1.0 )

    result = result - lx;

    return result;
}   // static inline double _VSTATIC(own_lgamma_pos_fp64) (double arg)

//! ===========================================================================
//! @brief 32-bit lgamma approximation
//!
//! @param[in] a     Argument pointer
//! @param[in] r     Result pointer
//! @return          Computation status
//! ===========================================================================
__attribute__((always_inline))
inline int __internal_slgamma_ep_cout (float *a, float *r)
{

    float x = (*a);
    float f = 0.0f, f1 = 0.0f;
    double ldx = 0.0, t0 = 0.0, t1 = 0.0, t2 = 0.0, result = 0.0, y = 0.0, y2 = 0.0;
    double p = 0.0, r1 = 0.0, r2 = 0.0;
    signed int ix = ((signed int) (((_iml_v2_sp_union_t *) & x)->hex[0]));
    unsigned int iabsx = ((((_iml_v2_sp_union_t *) & x)->hex[0]) & 0x7fffffff);
    unsigned int xsig = (((_iml_v2_sp_union_t *) & x)->hex[0] >> 31);
    unsigned int exp_x = ((((_iml_v2_sp_union_t *) & x)->hex[0] >> 23) & 0xFF);
    int i = 0, intx = 0;
    int signgam = 1;
    int nRet = 0;

    if (exp_x == 0xFF)
    {
        // For x==+/-infinity: return +infinity.
        // For x==NaN: raise invalid, return QNaN.
        (*r) = x * x;
    }
    else if (iabsx == 0x00000000u)
    {
        // x==+/-0
        if (xsig)
        {
            signgam = -1;
        }
        // Return +Infinity. Raise Zero divide.
        f = 0.0f;
        (*r) = 1.0f / f;
        nRet = 2;
    }
    else if (ix > 0x7C44AF8E)
    {
        // OVERFLOW_BOUNDARY <= x <= +Max_Double
        // Return +Infinity. Raise Inexact and Overflow.
        (*r) = (*(__constant double *) __slgamma_ep__PBIG) * (*(__constant double *) __slgamma_ep__PBIG);
        nRet = 3;
    }
    else
    {

        if (x >= 4.0f)  // x>4 fast Sergio Nemes branch
        {
            (*r) = __slgamma_ep_own_lgamma_fast_fp32 (x);
        }
        else if (!xsig) // x>=0 positive arguments domain
        {
            if (iabsx < 0x46000000u)
            {
                ldx = x;
                (*r) = __slgamma_ep_own_lgamma_pos_fp64 (ldx);
            }
            else    // if ( iabsx <= 0x7C44AF8Eu)
            {
                //
                // 2^13 <= x < OVERFLOW_BOUNDARY:
                // -----------------------------
                // Here we use algorithm based on the Stirling formula:
                // ln(GAMMA(x)) = ln(sqrt(2*Pi)) + (x-0.5)ln(x) - x
                //
                ldx = x;
                result = (*(__constant double *) __slgamma_ep__LN_SQRT_TWO_PI);
                t1 = ldx - 0.5;
                t2 = __slgamma_ep_own_log_lut_fp64 (x);
                t1 = t1 * t2;
                result = result + t1;
                result = result - ldx;
                (*r) = (float) result;
            }
        }   // if (!xsig) // x>=0 positive arguments domain
        else    // x<0 negative arguments domain
        {
            f = __slgamma_ep_own_nearbyint_fp32 (x);

            intx = (x == f);    /* Is x an integer? */

            if (!intx && (x > (__slgamma_ep__TWO_23H[1])) && !(((int) __slgamma_ep_own_ceilf_fp32 (x)) & 1))
            {
                // x belongs to interval (-2*k-1;-2*k) for some integer k>0.
                signgam = -1;
            }

            if (intx)
            {
                // x is negative integer
                // Return +Infinity. Raise Zero divide
                f = 0.0f;
                (*r) = 1.0f / f;
                nRet = 2;
            }
            else if (iabsx < 0x40000000u)
            {
                //
                // -2 < x < 0:
                // ------------
                // Reduction to interval [1;2)
                // using the formula
                // lgammaf(x) = lgammaf(x+1) - ln(abs(x))
                //
                y = x;
                p = 1.0;
                while (y < 1.0)
                {
                    p = p * y;
                    y = y + 1.0;
                }

                p = SPIRV_OCL_BUILTIN(fabs, _f64, ) (p);
                p = __slgamma_ep_own_log_lut_fp64 ((double) p);
                result = __slgamma_ep_own_lgamma_pos_fp64 (y);
                result = result - p;
                (*r) = (float) result;
            }   // else if ( iabsx < 0x40000000u )
            else if (iabsx < 0x40800000u)
            {
                //
                // -4 < x < -2:
                // --------------
                // At first we check if x is near 1.0 of 2.0 roots on [-i-1;-i)
                // and if so then we compute lgammaf(x) with special polynomials:
                // ln(GAMMA(x-x0)) = ln(GAMMA(x0)) + (x-x0)*P14(x-x0),
                // where x0 is corresponding root (rounded to double precision).
                // Else we use argument reduction to interval [1;2)
                // using the formula
                // lgammaf(x) = lgammaf(x+1) - ln(abs(x))
                //
                f = (-2.5) - x;
                f = f + (__slgamma_ep__TWO_23H[0]);
                i = ((((_iml_v2_sp_union_t *) & f)->hex[0]) & 0x00000001); // i=trunc(2-x)
                f = f - (__slgamma_ep__TWO_23H[0]);

                if ((((__constant double *) __slgamma_ep__LRIB)[3 * i + 0] < x) && (x < ((__constant double *) __slgamma_ep__LRIB)[3 * i + 2]))
                {
                    // x is near left root
                    y = x;
                    y = y - ((__constant double *) __slgamma_ep__LRIB)[3 * i + 1];
                    result = ((((__constant double *) __slgamma_ep__LRP)[4 * i + 0] * y
                               + ((__constant double *) __slgamma_ep__LRP)[4 * i + 1]) * y
                              + ((__constant double *) __slgamma_ep__LRP)[4 * i + 2]) * y + ((__constant double *) __slgamma_ep__LRP)[4 * i + 3];
                    result = result;
                }
                else if ((((__constant double *) __slgamma_ep__RRIB)[3 * i + 0] < x) && (x < ((__constant double *) __slgamma_ep__RRIB)[3 * i + 2]))
                {
                    // x is near right root
                    y = x;
                    y = y - ((__constant double *) __slgamma_ep__RRIB)[3 * i + 1];
                    result = ((((__constant double *) __slgamma_ep__RRP)[4 * i + 0] * y
                               + ((__constant double *) __slgamma_ep__RRP)[4 * i + 1]) * y
                              + ((__constant double *) __slgamma_ep__RRP)[4 * i + 2]) * y + ((__constant double *) __slgamma_ep__RRP)[4 * i + 3];
                    result = result;
                }
                else
                {
                    // x is far away from both roots.
                    y = x;
                    p = 1.0;
                    while (y < 1.0)
                    {
                        p = p * y;
                        y = y + 1.0;
                    }
                    p = SPIRV_OCL_BUILTIN(fabs, _f64, ) (p);
                    p = __slgamma_ep_own_log_lut_fp64 ((double) p);
                    result = __slgamma_ep_own_lgamma_pos_fp64 (y);
                    result = result - p;
                }
                (*r) = (float) result;
            }   // else if ( iabsx < 0x40800000u )
            else if (iabsx < 0x41100000u)
            {
                // -9 < x < -4
                // x is far away from both roots.
                y = x;
                p = 1.0;
                while (y < 1.0)
                {
                    p = p * y;
                    y = y + 1.0;
                }

                p = SPIRV_OCL_BUILTIN(fabs, _f64, ) (p);
                p = __slgamma_ep_own_log_lut_fp64 ((double) p);
                result = __slgamma_ep_own_lgamma_pos_fp64 (y);
                result = result - p;
                (*r) = (float) result;
            }   // else if ( iabsx < 0x41100000u )
            else if (iabsx < 0x46000000u)
            {
                //
                // -2^13 < x < -9:
                // ---------------
                // Here we use the formula:
                // ln(GAMMA(-x)) = ln(Pi/(x*GAMMA(x)*sin(Pi*x))) =
                // = -ln(x) - ln((GAMMA(x)) - ln(sin(Pi*r1)/(Pi*r1)) - ln(|r1|)
                // where r1 = x - rounded_to_nearest_integer(x), i.e |r1| <= 0.5
                // and ln(sin(Pi*r1)/(Pi*r1)) is approximated by
                // 8-degree polynomial of r1^2.
                //
                f = (__slgamma_ep__TWO_23H[0]) - x;
                f = f - (__slgamma_ep__TWO_23H[0]); // f=round(-x)
                ldx = x;
                ldx = -ldx;
                r1 = f;
                r1 = ldx - r1;
                r2 = r1 * r1;

                result = __slgamma_ep_own_log_lut_fp64 (-x);
                result = -result;
                y = __slgamma_ep_own_lgamma_pos_fp64 (ldx);
                result = result - y;

                t1 = r2 * r2;
                t0 = ((((*(__constant double *) __slgamma_ep__S14) * t1
                        + (*(__constant double *) __slgamma_ep__S10)) * t1
                       + (*(__constant double *) __slgamma_ep__S06)) * t1 + (*(__constant double *) __slgamma_ep__S02)) * r2;
                p = ((((*(__constant double *) __slgamma_ep__S16) * t1
                       + (*(__constant double *) __slgamma_ep__S12)) * t1
                      + (*(__constant double *) __slgamma_ep__S08)) * t1 + (*(__constant double *) __slgamma_ep__S04)) * t1;
                p = p + t0;

                result = result - p;

                r1 = SPIRV_OCL_BUILTIN(fabs, _f64, ) (r1);
                y = __slgamma_ep_own_log_lut_fp64 ((double) r1);
                result = result - y;
                (*r) = (float) result;
            }   // else if ( iabsx < 0x46000000u )
            else
            {
                //
                // Case x < -2^13:
                // ---------------
                // Here we use algorithm based on the Stirling formula:
                // ln(GAMMA(x)) = -ln(sqrt(2*Pi)) + (x-0.5)ln(|x|) -
                // - x - ln(sin(Pi*r1)/(Pi*r1)) - ln(|r1|)
                // where r1 = x - rounded_to_nearest_integer(x).
                //
                result = (*(__constant double *) __slgamma_ep__LN_SQRT_TWO_PI);
                ldx = x;
                t1 = ldx - 0.5;
                t2 = -ldx;
                t2 = __slgamma_ep_own_log_lut_fp64 (-x);
                t1 = t1 * t2;
                result = t1 - result;

                result = result - ldx;

                f = (__slgamma_ep__TWO_23H[0]);
                f = f - x;
                f = f - (__slgamma_ep__TWO_23H[0]);

                r1 = -ldx;
                r1 = r1 - f;
                r2 = r1 * r1;

                p = ((((((((*(__constant double *) __slgamma_ep__S16) * r2
                           + (*(__constant double *) __slgamma_ep__S14)) * r2
                          + (*(__constant double *) __slgamma_ep__S12)) * r2
                         + (*(__constant double *) __slgamma_ep__S10)) * r2
                        + (*(__constant double *) __slgamma_ep__S08)) * r2
                       + (*(__constant double *) __slgamma_ep__S06)) * r2
                      + (*(__constant double *) __slgamma_ep__S04)) * r2 + (*(__constant double *) __slgamma_ep__S02)) * r2;

                result = result - p;

                r1 = SPIRV_OCL_BUILTIN(fabs, _f64, ) (r1);
                y = __slgamma_ep_own_log_lut_fp64 ((double) r1);
                result = result - y;
                (*r) = (float) result;
            }   // else if ( intx )
        }   // else // x<0 negative arguments domain
    }   // else if ( exp_x == IML_EXPINF_32 )

    return nRet;
}   // inline int __internal_slgamma_ep_cout (float *a, float *r)

float __ocl_svml_lgammaf_ep (float a)
{
    float va1;
    float vr1;
    float r;

    va1 = a;
    __internal_slgamma_ep_cout (&va1, &vr1);
    r = vr1;

    return r;
}
